using System;
using System.IO;
using OhioState.AssetManaged;


namespace OhioState.Graphics.Proxy
{
    /// <summary>
    /// This represents shader routine.
    /// </summary>
    [Serializable()]
    public abstract class ShaderRoutine : SharedAsset
    {
        //
        // data members 
        //
        //private String shaderName;
        private String shaderContent;
        private String compileInfo;
        private bool routineCompiled;

        //
        // Constructor
        //
        public ShaderRoutine(String name)
            : base(name)
        {
            this.routineCompiled = false;
        }

        public ShaderRoutine(String name, String content)
            : base(name)
        {
            this.shaderContent = content;
            this.routineCompiled = false;
        }

        //
        // Copy Constructor
        //
        public ShaderRoutine(ShaderRoutine shader)
        {
            this.Name = shader.Name;
            this.shaderContent = shader.ShaderContent;
            this.compileInfo = shader.compileInfo;
            this.routineCompiled = shader.RoutineCompiled;
        }


        #region public properties
        public String ShaderContent
        {
            get { return this.shaderContent; }
            set
            {
                this.shaderContent = value;
                routineCompiled = false;
                this.FireUpdateChangedEvent(this);
            }
        }

        public String CompileInfo
        {
            get { return this.compileInfo; }
        }

        public bool RoutineCompiled
        {
            get { return this.routineCompiled; }
        }
        #endregion

        //
        // Accessor for compile info, routineCompiled
        //
        public void SetCompileInfo(String info)
        {
            this.compileInfo = info;
        }

        public void SetRoutineCompiled(bool compiled)
        {
            this.routineCompiled = compiled;
        }
        private uint _guid;
        public uint Guid
        {
            get { return _guid; }
            set { _guid = value; }
        }

        /// <summary>
        /// Overrides shared object ToString method
        /// </summary>
        /// <returns>A string representing this object's name</returns>
        public override string ToString()
        {
            return this.Name;
        }

        //
        // Clone - make a duplicate copy of this shader routine and return it
        //
        public abstract ShaderRoutine Clone();

        #region File operations
        //
        // LoadFromFile - static function that loads shader contents from a file
        //    Why is this even in here, as it is generic text I/O.
        //
        public static String LoadFromFile(String filename)
        {
            StreamReader sr = new StreamReader(filename);
            String fileContent = String.Empty;
            String retString = String.Empty;
            while ((fileContent = sr.ReadLine()) != null)
            {
                retString += fileContent;
                retString += Environment.NewLine;
            }
            sr.Close();

            return retString;
        }

        //
        // SaveToFile - function that saves shader contents to a file
        //  This is not static and is simply called on the current instance
        //    - Why not? Why is this even in here, as it is generic text I/O.
        //
        public void SaveToFile(String filename, String content, Stream stream)
        {
            StreamWriter sw;
            sw = new StreamWriter(stream);
            sw.WriteLine(content);
            sw.Close();
            this.ShaderContent = content;
            this.FireUpdateChangedEvent(this);
        }
        #endregion
    }

    [Serializable()]
    public class VertexShader : ShaderRoutine
    {
        public static VertexShader SolidColor = new VertexShader("InternalSolidColor", "void main()\n{\n   // transform vertex to clip space coordinates\n   gl_Position = ftransform();\n   // Set the color\n   gl_FrontColor = gl_Color;\n}");
        public static VertexShader VertexWithTexture = new VertexShader("VertexWithTexture", "void main()\n{\n // transform vertex to clip space coordinates \n gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n// Copy over the vertex color. \n gl_FrontColor = gl_Color; \n // transform vertex into texture space to get texture coord \n gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; \n}" );
        static VertexShader()
        {
            AssetManager.Instance.Add(SolidColor);
            AssetManager.Instance.Add(VertexWithTexture);
        }

        public VertexShader(String name)
            : base(name)
        {
        }

        public VertexShader(String name, String content)
            : base(name, content)
        {
        }

        //
        // Copy Constructor
        //
        public VertexShader(ShaderRoutine shader)
            : base(shader)
        {
        }

        public override ShaderRoutine Clone()
        {
            return new VertexShader(this);
        }
    }

    [Serializable()]
    public class FragmentShader : ShaderRoutine
    {
        public static FragmentShader SolidColor = new FragmentShader("InternalSolidColor", "void main()\n{\n   gl_FragColor = gl_Color;\n}");
        public static FragmentShader ModulateTexture = new FragmentShader("ModulateTexture", " uniform sampler2D texture; \n void main()\n{\n vec4 c = texture2D( texture, gl_TexCoord[0].st ); \n   // Texture has pre-multiplied alpha - the color does not. \n  vec4 color; \n color.rgb = gl_Color.rgb * gl_Color.a; \n color.a = gl_Color.a; \n  gl_FragColor = c * color;\n}");
        static FragmentShader()
        {
            AssetManager.Instance.Add(SolidColor);
            AssetManager.Instance.Add(ModulateTexture);
        }

        public FragmentShader(String name)
            : base(name)
        {
        }

        public FragmentShader(String name, String content)
            : base(name, content)
        {
        }

        //
        // Copy Constructor
        //
        public FragmentShader(ShaderRoutine shader)
            : base(shader)
        {
        }

        public override ShaderRoutine Clone()
        {
            return new FragmentShader(this);
        }
    }

}

